#include "NetIO.h"

Operation_Queue::Operation_Queue (void)
{
	completed_operations_ = new Operations;
	TAILQ_INIT (completed_operations_);
}

Operation_Queue::~Operation_Queue (void)
{
	Operation *op;

	cancel_all_operation ();

	while (!TAILQ_EMPTY (completed_operations_))
	{
		op = TAILQ_FIRST (completed_operations_);
		TAILQ_REMOVE (completed_operations_, op, field_);
		op->destroy ();
	}
}

bool Operation_Queue::enqueue_operation (EventHandle handle, Operation *op)
{
	operation_map::insert_result result =
	    operations_.insert (handle, op);

	if (!result.second)
	{
		Operation *lastop = result.first->second;
		TAILQ_CONCAT (lastop, op, field_);
		return false;
	}

	return true;
}

int Operation_Queue::has_operation (EventHandle handle)
{
	return operations_.find (handle) != operations_.end ();
}

bool Operation_Queue::cancel_operation (EventHandle handle)
{
	operation_map::iterator it = operations_.find (handle);

	if (it == operations_.end ())
		return false;

	Operation *lastop = it->second;
	Operation *curr_op;

	TAILQ_FOREACH (curr_op, lastop, field_)
	curr_op->errcode (IOCANCELED);
	TAILQ_CONCAT (completed_operations_, lastop, field_);
	operations_.erase (it);
	return true;
}

void Operation_Queue::cancel_all_operation ()
{
	Operation* curr_op;

	operation_map::iterator i = operations_.begin ();

	while (i != operations_.end ())
	{
		operation_map::iterator op_iter = i++;
		curr_op = op_iter->second;
		operations_.erase (op_iter);
		TAILQ_CONCAT (completed_operations_, curr_op, field_);
	}
}

int Operation_Queue::perform_operation (EventHandle handle)
{
	operation_map::iterator it = operations_.find (handle);

	if (it == operations_.end ())
		return 0;

	Operation *op = it->second;
	Operation *next_op;
#ifdef MODE_SPECULATIVE

	while (op)
	{
		if (op->perform ())
		{
			TAILQ_REMOVE (op, op, field_);
			next_op = TAILQ_FIRST (op);

			if (next_op)
				TAILQ_CONCAT (next_op, op, field_);

			it->second = next_op;
			TAILQ_INSERT_TAIL (completed_operations_, op, field_);
			op = it->second;
		}
		else
			return true;
	}

	operations_.erase (it);
	return false;

#else

	if (op->perform ())
	{
		TAILQ_REMOVE (op, op, field_);
		next_op = TAILQ_FIRST (op);

		if (next_op)
			TAILQ_CONCAT (next_op, op, field_);

		it->second = next_op;
		TAILQ_INSERT_TAIL (completed_operations_, op, field_);

		if (it->second)
			return true;
		else
		{
			operations_.erase (it);
			return false;
		}
	}
	else
		return true;

	return false;
#endif
}

void Operation_Queue::collect_handle_to_set (Handle_Set & handle_set)
{
	for (operation_map::iterator it = operations_.begin ();
	        it != operations_.end (); ++it)
	{
		handle_set.set_handle (it->first);
	}
}

void Operation_Queue::collect_connect_handle_to_set (Handle_Set & handle_set)
{
	for (operation_map::iterator it = operations_.begin ();
	        it != operations_.end (); ++it)
	{
		if (it->second->optype () == Operation::OPTYPE_CONNECT)
			handle_set.set_handle (it->first);
	}
}

void Operation_Queue::perform_operation_for_set (Handle_Set &handle_set)
{
	operation_map::iterator it = operations_.begin ();

	while (it != operations_.end ())
	{
		operation_map::iterator op_iter = it++;

		if (FD_ISSET (op_iter->first, &handle_set.get_fd_set ()))
		{
			perform_operation (op_iter->first);
		}
	}
}
